package org.heart.springsecurity.JwtToken;

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.AlgorithmMismatchException;
import com.auth0.jwt.exceptions.SignatureVerificationException;
import com.auth0.jwt.exceptions.TokenExpiredException;
import com.auth0.jwt.interfaces.DecodedJWT;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.heart.springsecurity.result.ApiResponse;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.PathMatcher;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;

import java.io.IOException;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;


public class JwtTokenFilter extends OncePerRequestFilter {
    private static final PathMatcher PATH_MATCHER = new AntPathMatcher();
    private final RedisTemplate<Object, Object> redisTemplate;

    public JwtTokenFilter(RedisTemplate<Object, Object> redisTemplate) {
        this.redisTemplate = redisTemplate;
    }


    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        String requestURI = request.getRequestURI();
        System.out.println("requestURI = " + requestURI);
        if (PATH_MATCHER.match("/auth/login", requestURI)) {
            filterChain.doFilter(request, response);
        } else {

            try {
                String token = request.getHeader("accessToken");
                String refreshToken = request.getHeader("refreshToken");
                //黑名单校验
                if (isTokenInBlacklist(token) && StringUtils.hasText(refreshToken)) {
                    writeErrorResponse(response, ApiResponse.fail(4001, "当前登入已失效"), HttpServletResponse.SC_OK);
                    return;
                }

                Algorithm algorithm = Algorithm.HMAC512("!*@&^%$#QAZPLGFSJWURHGJG");
                JWTVerifier verifier = JWT.require(algorithm)
                        .withIssuer("sys").build();
                DecodedJWT verify = verifier.verify(token);
                Date expiresAt = verify.getExpiresAt();
                Date now = new Date();
                Long userId = verify.getClaim("userId").asLong();

                System.out.println("userId = " + userId);

                List<String> scope = verify.getClaim("scope").asList(String.class);
                List<GrantedAuthority> authorities = scope.stream()
                        .map(scopeItem -> new SimpleGrantedAuthority("ROLE_" + scopeItem))
                        .collect(Collectors.toList());
                System.out.println("authorities = " + authorities);
                UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userId, null, authorities);
                SecurityContext context = SecurityContextHolder.createEmptyContext();
                context.setAuthentication(authentication);
                SecurityContextHolder.setContext(context);

                long timeDifference = expiresAt.getTime() - now.getTime();
                if (timeDifference < 1800000L) {
                    writeErrorResponse(response, ApiResponse.fail(4001, "当前登入已失效"), HttpServletResponse.SC_OK);
                    return;
                }



                filterChain.doFilter(request, response);
            } catch (SignatureVerificationException e) {
                writeErrorResponse(response, ApiResponse.fail(401, "请重新登入"), HttpServletResponse.SC_OK);
            } catch (TokenExpiredException e) {
                writeErrorResponse(response, ApiResponse.fail(401, "请重新登入"), HttpServletResponse.SC_OK);
            } catch (AlgorithmMismatchException e) {
                writeErrorResponse(response, ApiResponse.fail(401, "请重新登入"), HttpServletResponse.SC_OK);
            } catch (Exception e) {
                e.printStackTrace();
                writeErrorResponse(response, ApiResponse.fail(500, "系统异常"), HttpServletResponse.SC_OK);
            }
        }


    }

    private void writeErrorResponse(HttpServletResponse response, String message, int statusCode) throws IOException {
        response.setStatus(statusCode);
        response.setContentType("application/json;charset=UTF-8");
        response.getWriter().write(message);
        response.getWriter().flush();
        response.getWriter().close();
    }

    /**
     * 检查令牌是否在黑名单中
     *
     * @param token 要检查的令牌
     * @return 如果令牌在黑名单中，则返回true；否则返回false
     */
    private boolean isTokenInBlacklist(String token) {
        return Boolean.TRUE.equals(redisTemplate.hasKey(token));
    }


}